﻿using Core.Caching;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using StackExchange.Redis;
using ZiggyCreatures.Caching.Fusion;
using ZiggyCreatures.Caching.Fusion.Serialization;
using ZiggyCreatures.Caching.Fusion.Serialization.SystemTextJson;

namespace Infrastructure.Caching;

internal static class Extensions
{
    internal static IServiceCollection ConfigureCaching(this IServiceCollection services, IConfiguration configuration)
    {
        services.AddSingleton<IFusionCacheSerializer, FusionCacheSystemTextJsonSerializer>();

        var cacheOptions = configuration.GetSection(nameof(CacheOptions)).Get<CacheOptions>();
        if (cacheOptions == null || string.IsNullOrEmpty(cacheOptions.Redis))
        {
            services.AddDistributedMemoryCache();
            services.AddFusionCache()
           .WithDefaultEntryOptions(GetDefaultFusionOptions()) 
           .WithRegisteredDistributedCache();
            return services; 
        }

        services.AddFusionCache()
            .WithDefaultEntryOptions(GetDefaultFusionOptions()) 
            .WithRegisteredDistributedCache(); 

        services.AddStackExchangeRedisCache(options =>
        {
            options.Configuration = cacheOptions.Redis;
            options.ConfigurationOptions = new ConfigurationOptions
            {
                AbortOnConnectFail = true,
                ReconnectRetryPolicy = new LinearRetry(5000), 
                ConnectTimeout = 5000, 
                EndPoints = { cacheOptions.Redis! }
            };
        });

        return services;
    }

    private static FusionCacheEntryOptions GetDefaultFusionOptions() =>
        new FusionCacheEntryOptions
        {
            Duration = TimeSpan.FromMinutes(120),
            IsFailSafeEnabled = true,
            FailSafeMaxDuration = TimeSpan.FromHours(8),
            FailSafeThrottleDuration = TimeSpan.FromSeconds(30),
            FactorySoftTimeout = TimeSpan.FromSeconds(10),
            FactoryHardTimeout = TimeSpan.FromSeconds(30),
            AllowTimedOutFactoryBackgroundCompletion = true,
        };
}
